home *** CD-ROM | disk | FTP | other *** search
- /* Subroutines for insn-output.c for Macintosh.
- Several routines are taken from the generic 68k aux-output,
- the rest of this file is original code.
- Copyright (C) 1987 Free Software Foundation, Inc.
- Copyright (C) 1989, 1990 Apple Computer, Inc.
-
- This file is part of GNU CC.
-
- GNU CC is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "config.h"
- #include "rtl.h"
- #include "regs.h"
- #include "hard-reg-set.h"
- #include "real.h"
- #include "conditions.h"
- #include "insn-flags.h"
- #include "insn-config.h"
- #include "output.h"
- #include <stdio.h>
-
- int globalize_this;
-
- /* Size varies according to cmd option. */
-
- int long_double_type_size;
-
- /* Index into this array by (register number >> 3) to find the
- smallest class which contains that register. */
- enum reg_class regno_reg_class[]
- = { DATA_REGS, ADDR_REGS, FP_REGS };
-
- static rtx find_addr_reg ();
-
- #include "tree.h"
-
- rtx
- function_arg( CUMULATIVE_ARGS *cum, enum machine_mode mode, int named )
- {
- int i;
- if ( cum->p == NULL )
- return( 0 );
-
- if(cum->p->params[cum->count]==noreg)
- return( 0 );
-
- if( cum->p->params[cum->count] < 4 )
- i = cum->p->params[cum->count]-1;
- else
- i = cum->p->params[cum->count]+4;
- return( gen_rtx(REG, mode, i ));
- }
-
- rtx
- function_value( tree amode, tree decl )
- {
- int i;
-
- if ( (decl == NULL) || ((DECL_PARAM(decl) == NULL) || (DECL_PARAM(decl)->funcreturn==noreg)) )
- if (TARGET_68881 && (GET_MODE_CLASS (TYPE_MODE (amode)) == MODE_FLOAT) )
- return( gen_rtx(REG, TYPE_MODE (amode), 16 ) );
- else
- return( gen_rtx(REG, TYPE_MODE (amode), 0 ) );
- else {
-
- if( DECL_PARAM(decl)->funcreturn < pa0 )
- i = DECL_PARAM(decl)->funcreturn-1;
- else
- i = DECL_PARAM(decl)->funcreturn+4;
-
- return( gen_rtx(REG, TYPE_MODE (amode), i ));
- }
-
- }
-
- extern int current_function_is_pascal;
-
- rtx function_outgoing_value( tree amode, tree decl )
- {
- int i;
-
- if( decl != NULL )
- if ( (DECL_PARAM(decl) == NULL) || (DECL_PARAM(decl)->funcreturn==noreg) )
- if( current_function_is_pascal ) {
- return( gen_rtx (MEM, TYPE_MODE (amode),
- gen_rtx (PLUS, Pmode,
- frame_pointer_rtx,
- gen_rtx (CONST_INT, VOIDmode, 12345))) );
-
- }
- else
- return( function_value( amode, decl ) );
- else {
- if( DECL_PARAM(decl)->funcreturn < pa0 )
- i = DECL_PARAM(decl)->funcreturn-1;
- else
- i = DECL_PARAM(decl)->funcreturn+4;
-
- return( gen_rtx(REG, TYPE_MODE (amode), i ));
- }
- else
- return( function_value( amode, decl ) );
-
- }
-
- function_prologue (fp, size)
- FILE *fp;
- int size;
- {
- register int regno;
- char mask[100];
- extern char call_used_regs[];
- extern int frame_pointer_needed;
- int fsize = ((size) + 3) & -4;
-
- if (TARGET_FX30)
- fprintf (fp, "m#start:\n");
- mask[0] = '\0';
- if (frame_pointer_needed)
- {
- if (TARGET_68020 || fsize < 0x8000)
- fprintf (fp, "\tlink a6,#%d\n", -fsize);
- else
- fprintf (fp, TARGET_GAS?"\tlink a6,#0\n\tsubl #%d,sp\n":"\tlink a6,#0\n\tsub.l #%d,sp\n", fsize);
- }
- for (regno = 16; regno < 24; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- {
- strcat(mask, reg_names[regno]);
- strcat(mask, "/");
- }
- if (strlen(mask) > 0)
- {
- mask[strlen(mask)-1] = '\0';
- fprintf (fp, "\tfmovem %s,-(sp)\n", mask);
- }
- mask[0] = '\0';
- for (regno = 0; regno < 16; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[regno] &&
- !(frame_pointer_needed && regno == FRAME_POINTER_REGNUM))
- {
- strcat(mask, reg_names[regno]);
- strcat(mask, "/");
- }
- if (TARGET_FX30)
- {
- strcat(mask, reg_names[13]);
- strcat(mask, "/");
- }
- if (strlen(mask) > 0)
- {
- mask[strlen(mask)-1] = '\0';
- if (index(mask, '/') == 0)
- fprintf (fp, TARGET_GAS?"\tmovel %s,sp@-\n":"\tmove.l %s,-(sp)\n", mask);
- else
- fprintf (fp, TARGET_GAS?"\tmoveml %s,sp@-\n":"\tmovem.l %s,-(sp)\n", mask);
- }
- if (TARGET_FX30)
- {
- fprintf (fp, "\tDC.L $4bfb0170 ; lea -> a5\n");
- fprintf (fp, "\tDC.L _StaticDataArea-m#start-*+2\n");
- }
- /* Hook for tracing has to be called after everything else is set up. */
- if (generate_trace_calls)
- {
- if (!TARGET_GAS) fprintf (fp, "\tIMPORT %%_BP\n");
- fprintf (fp, "\tjsr %%_BP\n");
- }
- }
-
- /* Function epilogue code restores any saved regs and then returns. There
- are a number of obscure details and different options that can come up. */
-
- /* Note the Macsbug symbol output at the end (see Appendix G of Macsbug
- reference for details). */
-
- /* Also note that the pascal function return sequence is cribbed from MPW,
- for no particularly deep reason. */
-
- function_epilogue (fp, size)
- FILE *fp;
- int size;
- {
- register int regno;
- register int nregs;
- int offset, foffset, fpoffset;
- extern char call_used_regs[];
- extern int current_function_pops_args;
- extern int current_function_args_size;
- extern int current_function_is_pascal;
- extern int frame_pointer_needed;
- int fsize = ((size) + 3) & -4;
- int big = 0;
- char mask[100], fmask[100];
-
- /* Have to generate the trace calls after the return result is set up (by function
- body), but before any state restoration happens. */
- if (generate_trace_calls)
- {
- fprintf (fp, TARGET_GAS?"\tmovel d0,sp@-\n":"\tmove.l d0,-(a7)\n");
- if (!TARGET_GAS) fprintf (fp, "\tIMPORT %%_EP\n");
- fprintf (fp, "\tjsr %%_EP\n");
- fprintf (fp, TARGET_GAS?"\tmovel sp@+,d0\n":"\tmove.l (a7)+,d0\n");
- }
- /* Now compute which of all the registers has to be restored. */
- mask[0] = '\0'; fmask[0] = '\0';
- nregs = 0;
- for (regno = 16; regno < 24; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- { nregs++; strcat(fmask, reg_names[regno]); strcat(fmask, "/"); }
- foffset = nregs * 12;
- nregs = 0;
- if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0;
- for (regno = 0; regno < 16; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- { nregs++; strcat(mask, reg_names[regno]); strcat(mask, "/"); }
- if (TARGET_FX30)
- { nregs++; strcat(mask, reg_names[13]); strcat(mask, "/"); }
- offset = foffset + nregs * 4;
- if (offset + fsize >= 0x8000
- && frame_pointer_needed
- && (strlen(mask) > 0 || strlen(fmask) > 0))
- { fprintf (fp, TARGET_GAS?"\tmovel #%d,a0\n":"\tmove.l #%d,a0\n", -fsize);
- fsize = 0, big = 1; }
- if (strlen(mask) > 0) {
- mask[strlen(mask)-1] = '\0';
- if (index(mask, '/') == 0) {
- if (big)
- fprintf (fp, TARGET_GAS?"\tmovel a6@(-%d,a0:l),%s\n":"\tmove.l (-%d,a6,a0:l),%s\n", offset + fsize, mask);
- else if (! frame_pointer_needed)
- fprintf (fp, TARGET_GAS?"\tmovel sp@+,%s\n":"\tmove.l (sp)+,%s\n", mask);
- else
- fprintf (fp, TARGET_GAS?"\tmovel a6@(-%d),%s\n":"\tmove.l -%d(a6),%s\n", offset + fsize, mask);
- } else {
- if (big)
- fprintf (fp, TARGET_GAS?"\tmoveml a6@(-%d,a0.l),%s\n":"\tmovem.l (-%d,a6,a0.l),%s\n", offset + fsize, mask);
- else if (! frame_pointer_needed)
- fprintf (fp, TARGET_GAS?"\tmoveml sp@+,%s\n":"\tmovem.l (sp)+,%s\n", mask);
- else
- fprintf (fp, TARGET_GAS?"\tmoveml a6@(-%d),%s\n":"\tmovem.l -%d(a6),%s\n", offset + fsize, mask);
- }
- }
- if (strlen(fmask) > 0) {
- fmask[strlen(fmask)-1] = '\0';
- if (big)
- fprintf (fp, "\tfmovem (-%d,a6,a0.l),%s\n", foffset + fsize, fmask);
- else if (! frame_pointer_needed)
- fprintf (fp, "\tfmovem (sp)+,%s\n", fmask);
- else
- fprintf (fp, "\tfmovem -%d(a6),%s\n", foffset + fsize, fmask);
- }
- if (frame_pointer_needed)
- fprintf (fp, "\tunlk a6\n");
- /* if (current_function_pops_args && current_function_args_size)
- fprintf (fp, "\tDC.W $4e74, %d ; rtd\n",
- current_function_args_size
- + (current_function_returns_struct ? 4 : 0));
- else */ if (current_function_is_pascal && current_function_args_size > 0)
- fprintf (fp, TARGET_GAS?"\tmovel sp@+,a0\n\taddw #%d,sp\n\tjmp a0@\n":"\tmovea.l (sp)+,a0\n\tadd.w #%d,sp\n\tjmp (a0)\n",
- current_function_args_size);
- /* else if (current_function_returns_struct)
- fprintf (fp, "\tDC.W $4e74, 4 ; rtd #4\n"); */
- else
- fprintf (fp, "\trts\n");
- if (TARGET_MACSBUG)
- {
- extern char *current_function_name;
- int len = strlen(current_function_name);
-
- if (len < 32)
- ASM_OUTPUT_BYTE(fp,0x80 + len);
- else
- {
- ASM_OUTPUT_BYTE(fp,0x80);
- ASM_OUTPUT_BYTE(fp,len);
- }
- fprintf (fp, TARGET_GAS?"\t.ascii \"%s\"\n":"\tDC.B '%s'\n", current_function_name);
- if (len < 32)
- {
- if ((len+1) & 1) ASM_OUTPUT_BYTE(fp,0);
- }
- else
- {
- if ((len+2) & 1) ASM_OUTPUT_BYTE(fp,0);
- }
- }
- /* Unconditional, so the "local data length" gets written properly */
- dump_local_strings (fp);
- }
-
- char *
- output_btst (operands, countop, dataop, insn, signpos)
- rtx *operands;
- rtx countop, dataop;
- rtx insn;
- int signpos;
- {
- operands[0] = countop;
- operands[1] = dataop;
- if (GET_CODE (countop) == CONST_INT)
- {
- register int count = INTVAL (countop);
- if (count == signpos)
- cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N;
- else
- cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N;
-
- if (count == 31
- && next_insns_test_no_inequality (insn))
- return "tst%.l %1";
- if (count == 15
- && next_insns_test_no_inequality (insn))
- return "tst%.w %1";
- if (count == 7
- && next_insns_test_no_inequality (insn))
- return "tst%.b %1";
-
- cc_status.flags = CC_NOT_NEGATIVE;
- }
- return "btst %0,%1";
- }
-
- /* Return the best assembler insn template
- for moving operands[1] into operands[0] as a fullword. */
-
- static char *
- singlemove_string (operands)
- rtx *operands;
- {
- if (operands[1] != const0_rtx)
- return "move%.l %1,%0";
- if (! ADDRESS_REG_P (operands[0]))
- return "clr%.l %0";
- return "sub%.l %0,%0";
- }
-
- /* Output assembler code to perform a doubleword move insn
- with operands OPERANDS. */
-
- char *
- output_move_double (operands)
- rtx *operands;
- {
- enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
- rtx latehalf[2];
- rtx addreg0 = 0, addreg1 = 0;
-
- /* First classify both operands. */
-
- if (REG_P (operands[0]))
- optype0 = REGOP;
- else if (offsettable_memref_p (operands[0]))
- optype0 = OFFSOP;
- else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
- optype0 = POPOP;
- else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
- optype0 = PUSHOP;
- else if (GET_CODE (operands[0]) == MEM)
- optype0 = MEMOP;
- else
- optype0 = RNDOP;
-
- if (REG_P (operands[1]))
- optype1 = REGOP;
- else if (CONSTANT_P (operands[1])
- || GET_CODE (operands[1]) == CONST_DOUBLE)
- optype1 = CNSTOP;
- else if (offsettable_memref_p (operands[1]))
- optype1 = OFFSOP;
- else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
- optype1 = POPOP;
- else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
- optype1 = PUSHOP;
- else if (GET_CODE (operands[1]) == MEM)
- optype1 = MEMOP;
- else
- optype1 = RNDOP;
-
- /* Check for the cases that the operand constraints are not
- supposed to allow to happen. Abort if we get one,
- because generating code for these cases is painful. */
-
- if (optype0 == RNDOP || optype1 == RNDOP)
- abort ();
-
- /* If one operand is decrementing and one is incrementing
- decrement the former register explicitly
- and change that operand into ordinary indexing. */
-
- if (optype0 == PUSHOP && optype1 == POPOP)
- {
- operands[0] = XEXP (XEXP (operands[0], 0), 0);
- output_asm_insn ("subq%.l #8,%0", operands);
- operands[0] = gen_rtx (MEM, DImode, operands[0]);
- optype0 = OFFSOP;
- }
- if (optype0 == POPOP && optype1 == PUSHOP)
- {
- operands[1] = XEXP (XEXP (operands[1], 0), 0);
- output_asm_insn ("subq%.l #8,%1", operands);
- operands[1] = gen_rtx (MEM, DImode, operands[1]);
- optype1 = OFFSOP;
- }
-
- /* If an operand is an unoffsettable memory ref, find a register
- we can increment temporarily to make it refer to the second word. */
-
- if (optype0 == MEMOP)
- addreg0 = find_addr_reg (XEXP (operands[0], 0));
-
- if (optype1 == MEMOP)
- addreg1 = find_addr_reg (XEXP (operands[1], 0));
-
- /* Ok, we can do one word at a time.
- Normally we do the low-numbered word first,
- but if either operand is autodecrementing then we
- do the high-numbered word first.
-
- In either case, set up in LATEHALF the operands to use
- for the high-numbered word and in some cases alter the
- operands in OPERANDS to be suitable for the low-numbered word. */
-
- if (optype0 == REGOP)
- latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
- else if (optype0 == OFFSOP)
- latehalf[0] = adj_offsettable_operand (operands[0], 4);
- else
- latehalf[0] = operands[0];
-
- if (optype1 == REGOP)
- latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
- else if (optype1 == OFFSOP)
- latehalf[1] = adj_offsettable_operand (operands[1], 4);
- else if (optype1 == CNSTOP)
- {
- if (CONSTANT_P (operands[1]))
- latehalf[1] = const0_rtx;
- else if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- union { REAL_VALUE_TYPE e; int i[3]; } ue;
- union { double d; int i[2]; } ud;
-
- ue.i[0] = CONST_DOUBLE_LOW (operands[1]);
- ue.i[1] = CONST_DOUBLE_HIGH (operands[1]);
- ue.i[2] = CONST_DOUBLE_TOP (operands[1]);
-
- ud.d = ue.e;
-
- latehalf[1] = gen_rtx (CONST_INT, VOIDmode, ud.i[1]);
- operands[1] = gen_rtx (CONST_INT, VOIDmode, ud.i[0]);
- }
- }
- else
- latehalf[1] = operands[1];
-
- /* If insn is effectively movd N(sp),-(sp) then we will do the
- high word first. We should use the adjusted operand 1 (which is N+4(sp))
- for the low word as well, to compensate for the first decrement of sp. */
- if (optype0 == PUSHOP
- && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
- && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
- operands[1] = latehalf[1];
-
- /* If one or both operands autodecrementing,
- do the two words, high-numbered first. */
-
- /* Likewise, the first move would clobber the source of the second one,
- do them in the other order. This happens only for registers;
- such overlap can't happen in memory unless the user explicitly
- sets it up, and that is an undefined circumstance. */
-
- if (optype0 == PUSHOP || optype1 == PUSHOP
- || (optype0 == REGOP && optype1 == REGOP
- && REGNO (operands[0]) == REGNO (latehalf[1])))
- {
- /* Make any unoffsettable addresses point at high-numbered word. */
- if (addreg0)
- output_asm_insn ("addql #4,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("addql #4,%0", &addreg1);
-
- /* Do that word. */
- output_asm_insn (singlemove_string (latehalf), latehalf);
-
- /* Undo the adds we just did. */
- if (addreg0)
- output_asm_insn ("subql #4,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("subql #4,%0", &addreg1);
-
- /* Do low-numbered word. */
- output_asm_insn (singlemove_string (operands), operands);
-
- return "";
- }
-
- /* Normal case: do the two words, low-numbered first. */
-
- output_asm_insn (singlemove_string (operands), operands);
-
- /* Make any unoffsettable addresses point at high-numbered word. */
- if (addreg0)
- output_asm_insn ("addql #4,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("addql #4,%0", &addreg1);
-
- /* Do that word. */
- output_asm_insn (singlemove_string (latehalf), latehalf);
-
- /* Undo the adds we just did. */
- if (addreg0)
- output_asm_insn ("subql #4,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("subql #4,%0", &addreg1);
-
- return "";
- }
-
- /* Output assembler code to perform a long double move insn
- with operands OPERANDS. */
-
- char *
- output_move_extended (operands)
- rtx *operands;
- {
- enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
- rtx latehalf[2], thirdhalf[2];
- rtx addreg0 = 0, addreg1 = 0;
-
- /* First classify both operands. */
-
- if (REG_P (operands[0]))
- optype0 = REGOP;
- else if (offsettable_memref_p (operands[0]))
- optype0 = OFFSOP;
- else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
- optype0 = POPOP;
- else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
- optype0 = PUSHOP;
- else if (GET_CODE (operands[0]) == MEM)
- optype0 = MEMOP;
- else
- optype0 = RNDOP;
-
- if (REG_P (operands[1]))
- optype1 = REGOP;
- else if (CONSTANT_P (operands[1])
- || GET_CODE (operands[1]) == CONST_DOUBLE)
- optype1 = CNSTOP;
- else if (offsettable_memref_p (operands[1]))
- optype1 = OFFSOP;
- else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
- optype1 = POPOP;
- else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
- optype1 = PUSHOP;
- else if (GET_CODE (operands[1]) == MEM)
- optype1 = MEMOP;
- else
- optype1 = RNDOP;
-
- /* Check for the cases that the operand constraints are not
- supposed to allow to happen. Abort if we get one,
- because generating code for these cases is painful. */
-
- if (optype0 == RNDOP || optype1 == RNDOP || optype0 == MEMOP || optype1 == MEMOP)
- abort ();
-
- /* If one operand is decrementing and one is incrementing
- decrement the former register explicitly
- and change that operand into ordinary indexing. */
-
- if (optype0 == PUSHOP && optype1 == POPOP)
- {
- operands[0] = XEXP (XEXP (operands[0], 0), 0);
- output_asm_insn ("subq%.l #12345,%0", operands);
- operands[0] = gen_rtx (MEM, DImode, operands[0]);
- optype0 = OFFSOP;
- }
- if (optype0 == POPOP && optype1 == PUSHOP)
- {
- operands[1] = XEXP (XEXP (operands[1], 0), 0);
- output_asm_insn ("subq%.l #12345,%1", operands);
- operands[1] = gen_rtx (MEM, DImode, operands[1]);
- optype1 = OFFSOP;
- }
-
- /* Ok, we can do one word at a time.
- Normally we do the low-numbered word first,
- but if either operand is autodecrementing then we
- do the high-numbered word first.
-
- In either case, set up in LATEHALF the operands to use
- for the high-numbered word and in some cases alter the
- operands in OPERANDS to be suitable for the low-numbered word. */
-
- if (optype0 == REGOP)
- latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
- else if (optype0 == OFFSOP)
- latehalf[0] = adj_offsettable_operand (operands[0], (TARGET_68881 ? 4 :2));
- else
- latehalf[0] = operands[0];
-
- if (optype1 == REGOP)
- latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
- else if (optype1 == OFFSOP)
- latehalf[1] = adj_offsettable_operand (operands[1], (TARGET_68881 ? 4 :2));
- else if (optype1 == CNSTOP)
- {
- if (CONSTANT_P (operands[1]))
- latehalf[1] = const0_rtx;
- else if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
- CONST_DOUBLE_HIGH (operands[1]));
- }
- }
- else
- latehalf[1] = operands[1];
-
- if (optype0 == REGOP)
- thirdhalf[0] = gen_rtx (REG, SImode,
- ((!TARGET_68881 && REGNO (operands[0]) == 0) ?
- 8 :
- REGNO (operands[0]) + 2));
- else if (optype0 == OFFSOP)
- thirdhalf[0] = adj_offsettable_operand (operands[0], (TARGET_68881 ? 8:6));
- else
- thirdhalf[0] = operands[0];
-
- if (optype1 == REGOP)
- thirdhalf[1] = gen_rtx (REG, SImode,
- ((!TARGET_68881 && REGNO (operands[1]) == 0) ?
- 8 :
- REGNO (operands[1]) + 2));
- else if (optype1 == OFFSOP)
- thirdhalf[1] = adj_offsettable_operand (operands[1], (TARGET_68881 ? 8:6));
- else if (optype1 == CNSTOP)
- {
- if (CONSTANT_P (operands[1]))
- thirdhalf[1] = const0_rtx;
- else if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- thirdhalf[1] = gen_rtx (CONST_INT, VOIDmode,
- CONST_DOUBLE_TOP (operands[1]));
- operands[1] = gen_rtx (CONST_INT, VOIDmode,
- (TARGET_68881 ? CONST_DOUBLE_LOW (operands[1])
- : ((unsigned int) CONST_DOUBLE_LOW (operands[1])) >> 16));
- }
- }
- else
- thirdhalf[1] = operands[1];
-
- /* If insn is effectively movd N(sp),-(sp) then we will do the
- high word first. We should use the adjusted operand 1 (which is N+4(sp))
- for the low word as well, to compensate for the first decrement of sp. */
- if (optype0 == PUSHOP
- && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
- && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
- operands[1] = latehalf[1];
-
- /* If one or both operands autodecrementing,
- do the two words, high-numbered first. */
-
-
- /* Likewise, the first move would clobber the source of the second one,
- do them in the other order. This happens only for registers;
- such overlap can't happen in memory unless the user explicitly
- sets it up, and that is an undefined circumstance. */
-
- if (optype0 == PUSHOP || optype1 == PUSHOP
- || (optype0 == REGOP && optype1 == REGOP
- && REGNO (operands[0]) == REGNO (latehalf[1])))
- {
- output_asm_insn (singlemove_string (thirdhalf), thirdhalf);
-
- output_asm_insn (singlemove_string (latehalf), latehalf);
-
- if (TARGET_68881)
- output_asm_insn (singlemove_string (operands), operands);
- else
- output_asm_insn ("move%.w %1,%0", operands);
-
- return "";
- }
-
- /* Normal case: do the three words, low-numbered first. */
-
- if (TARGET_68881)
- output_asm_insn (singlemove_string (operands), operands);
- else
- output_asm_insn ("move%.w %1,%0", operands);
-
- output_asm_insn (singlemove_string (latehalf), latehalf);
-
- output_asm_insn (singlemove_string (thirdhalf), thirdhalf);
-
- return "";
- }
-
- /* Generate code for one of the extended-to-integer lib calls. The context
- is such that we can't make call rtxes, and have to do it all manually. */
-
- char *
- output_lib_convert (operands, name)
- rtx *operands;
- char *name;
- {
- rtx aoperands[2];
- char tmpbuf[1000];
- int pushed = 0;
-
- /* What regs need to be saved/restored? probably several... */
- /* Set up a new operand array. */
- aoperands[0] = gen_rtx (MEM, GET_MODE (aoperands[1]),
- gen_rtx (PRE_DEC, Pmode, stack_pointer_rtx));
- aoperands[1] = operands[1];
- /* We need a pointer to the float; try different ways to get one. */
- if (GET_CODE (aoperands[1]) == MEM)
- {
- output_asm_insn ("pea %1", aoperands);
- }
- else if (FP_REG_P (aoperands[1]))
- {
- output_asm_insn ("fmove.x %1,%0", aoperands);
- output_asm_insn (TARGET_GAS?"pea sp@(0)":"pea 0(sp)", NULL);
- pushed = 1;
- }
- else
- {
- output_move_extended (aoperands);
- output_asm_insn (TARGET_GAS?"pea sp@(0)":"pea 0(sp)", NULL);
- pushed = 1;
- }
- /* Do an on-the-spot importation of the libcall name. */
- if (!TARGET_GAS)
- {
- sprintf (tmpbuf, "IMPORT %s", name);
- output_asm_insn (tmpbuf, NULL);
- }
- /* Now go and do it. */
- if (TARGET_FX30)
- sprintf (tmpbuf, "DC.W $61ff ; bsr.l\;DC.L %s-m#start-*", name);
- else
- sprintf (tmpbuf, "jsr %s", name);
- output_asm_insn (tmpbuf, NULL);
- /* If intended result place is not d0, move it there. */
- if (! (REG_P (operands[0]) && REGNO (operands[0]) == 0))
- {
- aoperands[0] = operands[0];
- aoperands[1] = gen_rtx (REG, SImode, 0);
- output_asm_insn (singlemove_string (aoperands), aoperands);
- }
- /* Fix up the stack (we pushed a pointer and maybe an extended float
- for it to point to). */
- sprintf (tmpbuf, "add%.w #%d,sp",
- 4 + (pushed ? mode_size[(int) XFmode] : 0));
- output_asm_insn(tmpbuf, NULL);
- return "";
- }
-
- /* The int library call convention is to use D0 and D1 with output to D0.
- The complication here is that regalloc is already complete, so we have
- to be very careful not to step on any important values. From md we
- *are* guaranteed that output is a Dn, while input is either Dn or a
- constant, which simplifies things considerably. */
-
- /* (I'm not 100% convinced that this code is correct...) */
-
- char *
- output_int_lib_call (operands, name)
- rtx *operands;
- char *name;
- {
- char tmpbuf[1000];
- int o0d0 = 0, o2d0 = 0, o0d1 = 0, o2d1 = 0, o0d2 = 0;
-
- /* Int lib routines may step on a0. */
- output_asm_insn (TARGET_GAS?"moveml a0/a1,sp@-":"movem.l a0/a1,-(sp)", NULL);
-
- if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 0) o0d0 = 1;
- if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 1) o0d1 = 1;
- if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 2) o0d2 = 1;
- if (GET_CODE (operands[2]) == REG && REGNO (operands[2]) == 0) o2d0 = 1;
- if (GET_CODE (operands[2]) == REG && REGNO (operands[2]) == 1) o2d1 = 1;
-
- if (!o0d1)
- output_asm_insn (TARGET_GAS?"movel d1,sp@-":"move.l d1,-(sp)", NULL);
-
- if (!o0d2)
- output_asm_insn (TARGET_GAS?"movel d2,sp@-":"move.l d2,-(sp)", NULL);
-
- if (o0d0)
- {
- if (o2d1)
- {
- /* everything is exactly where we want it */
- }
- else
- {
- /* move operand 2 into d1. */
- output_asm_insn ("move%.l %2,d1", operands);
- }
- }
- else
- {
- /* operand 0 is not in d0, so we need to save d0 on the stack before
- copying the operand to d0. */
- output_asm_insn (TARGET_GAS?"movel d0,sp@-":"move.l d0,-(sp)", NULL);
- if (o0d1)
- {
- output_asm_insn ("move%.l d1,d0", NULL);
- if (o2d0)
- {
- /* Input and output are in exactly the opposite of where we want. */
- /* d0 just got saved on the stack, so we can copy it from the stack
- to d1. Note that we are copying the value not popping it off, so
- that we can restore d0 later. */
- output_asm_insn (TARGET_GAS?"movel sp@,d1":"move.l (sp),d1", NULL);
- }
- else
- {
- /* move the input to d1. */
- output_asm_insn ("movel %2,d1", operands);
- }
- }
- else
- {
- if (!o2d1)
- {
- /* operand 2 is not in d1, so we gotta move it to d1 */
- output_asm_insn ("move%.l %2,d1", operands);
- }
- /* operand 0 is not in either d0 or d1, so we gotta move it to d0 */
- output_asm_insn ("move%.l %0,d0", operands);
- }
- }
-
- /* Do the int lib call proper now. */
- if (!TARGET_GAS)
- {
- sprintf (tmpbuf, "IMPORT %s", name);
- output_asm_insn (tmpbuf, NULL);
- }
- if (TARGET_FX30)
- sprintf (tmpbuf, "DC.W $61ff ; bsr.l\;DC.L %s-m#start-*", name);
- else
- sprintf (tmpbuf, "jsr %s", name);
- output_asm_insn (tmpbuf, NULL);
-
- /* Now clean up any mess we might have made on the stack, plus move the
- result from d0 to wherever it was supposed to go. */
-
- /* If operand 0 was not in d0, move the output to the correct place and then
- restore d0 */
- if (!o0d0)
- {
- output_asm_insn ("move%.l d0,%0", operands);
- output_asm_insn (TARGET_GAS?"movel sp@+,d0":"move.l (sp)+,d0", NULL);
- }
-
- if (!o0d2)
- output_asm_insn (TARGET_GAS?"movel sp@+,d2":"move.l (sp)+,d2", NULL);
-
- if (!o0d1)
- output_asm_insn (TARGET_GAS?"movel sp@+,d1":"move.l (sp)+,d1", NULL);
-
- /* restore a0, a1, d1, and d2 */
- output_asm_insn (TARGET_GAS?"moveml sp@+,a0/a1":"movem.l (sp)+,a0/a1", NULL);
-
- return "";
- }
-
- /* Helper stuff for SANE output routines. */
-
- #define STKOFF(MODE,OFF) \
- gen_rtx (MEM, (MODE), gen_rtx (PLUS, Pmode, stack_pointer_rtx, \
- gen_rtx (CONST_INT, VOIDmode, (OFF))))
-
- /* This takes a stack reference and changes it into a stack reference
- 4 bytes deeper. This is needed after a push on the stack. */
-
- rtx deepen (x)
- rtx x;
- {
- if (GET_CODE (x) == MEM
- && GET_CODE (XEXP (x, 0)) == PLUS
- && XEXP (XEXP (x, 0), 0) == stack_pointer_rtx)
- {
- return STKOFF (GET_MODE (x), 4 + INTVAL (XEXP (XEXP (x, 0), 1)));
- }
- else
- return x;
- }
-
- /* Output a 2(1)-address operation that uses SANE. */
-
- char *
- output_sane_2 (opnds, op, name)
- rtx *opnds;
- int op;
- char *name;
- {
- char tmpbuf[100], *cname;
- enum machine_mode mode0 = GET_MODE (opnds[0]);
- int space0 = 0, spacetmp = 0, space;
- int cop;
- rtx operands[2], moperands[2], coperands[2], tmprtx;
-
- if (mode0 != XFmode)
- spacetmp = GET_MODE_SIZE (XFmode);
- if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
- space0 = GET_MODE_SIZE (GET_MODE (opnds[0]));
- space = spacetmp + space0;
- /* Reserve needed space for all our tmps and operands. */
- if (spacetmp > 0)
- {
- sprintf(tmpbuf,"sub%.w #%d,sp", spacetmp);
- output_asm_insn(tmpbuf, NULL);
- tmprtx = STKOFF (XFmode, space0);
- }
- if (space0 > 0)
- {
- output_sane_push(opnds[0]);
- operands[0] = STKOFF (GET_MODE (opnds[0]), 0);
- }
- else
- {
- operands[0] = opnds[0];
- }
- /* Now everything is a pointer to memlocs where the numbers reside. */
- /* First order of business is to make sure the input-output operand
- is of extended type. If not, then we convert into a reserved place
- and if so, we maybe put it on the stack anyway. */
- if (mode0 != XFmode)
- {
- cop = (mode0 == HImode ? 0x200e :
- (mode0 == SImode ? 0x280e :
- (mode0 == SFmode ? 0x100e :
- 0x080e)));
- cname = (mode0 == HImode ? "FI2X" :
- (mode0 == SImode ? "FL2X" :
- (mode0 == SFmode ? "FS2X" :
- "FD2X")));
- coperands[1] = operands[0];
- coperands[0] = deepen (tmprtx);
- output_sane_op (coperands, 2, cop, cname);
- moperands[0] = tmprtx;
- }
- else
- {
- moperands[0] = operands[0];
- }
- /* Now we're all set to do the operation proper. */
- output_sane_op (moperands, 1, op, name);
- /* The result of the operation is still extended, so we may need to
- do another conversion. Fortunately, the extended result is already in
- memory, so we don't need to allocate, but the final result may need
- to be sent back to regs. */
- if (mode0 != XFmode)
- {
- cop = (mode0 == HImode ? 0x2010 :
- (mode0 == SImode ? 0x2810 :
- (mode0 == SFmode ? 0x1010 :
- 0x0810)));
- cname = (mode0 == HImode ? "FX2I" :
- (mode0 == SImode ? "FX2L" :
- (mode0 == SFmode ? "FX2S" :
- "FX2D")));
- coperands[0] = deepen (operands[0]);
- coperands[1] = moperands[0];
- output_sane_op (coperands, 2, cop, cname);
- }
- /* SANE calls all done, now clean up. */
- /* Pop the result if it had to be pushed originally. */
- if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
- {
- output_sane_pop (opnds[0]);
- }
- /* Deallocate everything else. */
- if (spacetmp > 0)
- {
- sprintf (tmpbuf, "add%.w #%d,sp", spacetmp);
- output_asm_insn(tmpbuf, NULL);
- }
- /* All the code has already been dumped out. */
- return "";
- }
-
- /* Output a compare operation that uses SANE (two float operands, integer
- result). */
-
- char *
- output_sane_cmp (opnds, op, name)
- rtx *opnds;
- int op;
- char *name;
- {
- char tmpbuf[100], *cname;
- enum machine_mode mode0 = GET_MODE (opnds[0]);
- enum machine_mode mode1 = GET_MODE (opnds[1]);
- int space0 = 0, space1 = 0, spacetmp = 0, space;
- int cop;
- rtx operands[3], moperands[3], coperands[2], tmprtx, tmpop;
-
- if (mode0 != XFmode)
- spacetmp = GET_MODE_SIZE (XFmode);
- if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
- space0 = GET_MODE_SIZE (GET_MODE (opnds[0]));
- if (REG_P (opnds[1]) || GET_CODE (opnds[1]) == CONST_DOUBLE)
- space1 = GET_MODE_SIZE (GET_MODE (opnds[1]));
- space = spacetmp + space1 + space0;
- /* Reserve needed space for all our tmps and operands. */
- if (spacetmp > 0)
- {
- sprintf(tmpbuf, "sub%.w #%d,sp", spacetmp);
- output_asm_insn(tmpbuf, NULL);
- tmprtx = STKOFF (XFmode, space0 + space1);
- }
- if (space1 > 0)
- {
- output_sane_push(opnds[1]);
- operands[1] = STKOFF (GET_MODE (opnds[1]), space0);
- }
- else
- {
- operands[1] = opnds[1];
- }
- if (space0 > 0)
- {
- output_sane_push(opnds[0]);
- operands[0] = STKOFF (GET_MODE (opnds[0]), 0);
- }
- else
- {
- operands[0] = opnds[0];
- }
- /* Now everything is a pointer to memlocs where the numbers reside. */
- /* First order of business is to make sure the first operand
- is of extended type. If not, then we convert into a reserved place
- and if so, we maybe put it on the stack anyway. */
- if (mode0 != XFmode)
- {
- cop = (mode0 == HImode ? 0x200e :
- (mode0 == SImode ? 0x280e :
- (mode0 == SFmode ? 0x100e :
- 0x080e)));
- cname = (mode0 == HImode ? "FI2X" :
- (mode0 == SImode ? "FL2X" :
- (mode0 == SFmode ? "FS2X" :
- "FD2X")));
- coperands[1] = operands[0];
- coperands[0] = deepen (tmprtx);
- output_sane_op (coperands, 2, cop, cname);
- moperands[0] = tmprtx;
- }
- else
- {
- moperands[0] = operands[0];
- }
- tmpop = moperands[0];
- moperands[0] = deepen (moperands[0]);
- moperands[1] = operands[1];
- /* Now we're all set to do the comparison proper. */
- output_sane_op (moperands, 2, op, name);
- /* Deallocate everything else. Note that this add is really adda,
- so condition codes coming back from SANE op are still valid. */
- if (spacetmp + space1 + space0 > 0)
- {
- sprintf (tmpbuf, "add%.w #%d,sp", spacetmp + space1 + space0);
- output_asm_insn(tmpbuf, NULL);
- }
- /* All the code has already been dumped out. */
- return "";
- }
-
- /* Output a compare against 0 by synthesizing the zero and calling cmp. */
-
- char *
- output_sane_tst (opnds, op, name)
- rtx *opnds;
- int op;
- char *name;
- {
- enum machine_mode mode0 = GET_MODE (opnds[0]);
- rtx operands[2];
-
- operands[0] = opnds[0];
- operands[1] = CONST0_RTX (mode0);
- return output_sane_cmp (operands, op, name);
- }
-
- /* Output a conversion operation that uses SANE. This is sort of like
- a two-address operation, except that conversions aren't needed... */
-
- char *
- output_sane_convert (opnds)
- rtx *opnds;
- {
- char tmpbuf[100], *cname;
- enum machine_mode frommode = GET_MODE (opnds[1]);
- enum machine_mode tomode = GET_MODE (opnds[0]);
- int space0 = 0, space1 = 0, spacetmp = 0, space;
- int cop;
- rtx operands[3], moperands[3], coperands[2], tmprtx, tmpop;
-
- if (frommode == tomode) abort(); /* should never happen? */
-
- if (frommode != XFmode && tomode != XFmode)
- spacetmp = GET_MODE_SIZE (XFmode);
- if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
- space0 = GET_MODE_SIZE (GET_MODE (opnds[0]));
- if (REG_P (opnds[1]) || GET_CODE (opnds[1]) == CONST_DOUBLE)
- space1 = GET_MODE_SIZE (GET_MODE (opnds[1]));
- space = spacetmp + space1 + space0;
- /* Reserve needed space for all our tmps and operands. */
- if (spacetmp > 0)
- {
- sprintf(tmpbuf, "sub%.w #%d,sp", spacetmp);
- output_asm_insn(tmpbuf, NULL);
- tmprtx = STKOFF (XFmode, space0 + space1);
- }
- if (space1 > 0)
- {
- output_sane_push(opnds[1]);
- operands[1] = STKOFF (GET_MODE (opnds[1]), space0);
- }
- else
- {
- operands[1] = opnds[1];
- }
- if (space0 > 0)
- {
- output_sane_push(opnds[0]);
- operands[0] = STKOFF (GET_MODE (opnds[0]), 0);
- }
- else
- {
- operands[0] = opnds[0];
- }
- if (frommode != XFmode)
- {
- cop = (frommode == HImode ? 0x200e :
- (frommode == SImode ? 0x280e :
- (frommode == SFmode ? 0x100e :
- 0x080e)));
- cname = (frommode == HImode ? "FI2X" :
- (frommode == SImode ? "FL2X" :
- (frommode == SFmode ? "FS2X" :
- "FD2X")));
- coperands[1] = operands[1];
- coperands[0] = deepen (tomode == XFmode ? operands[0] : tmprtx);
- output_sane_op (coperands, 2, cop, cname);
- }
- /* If necessary, do the second conversion. */
- if (tomode != XFmode)
- {
- cop = (tomode == HImode ? 0x2010 :
- (tomode == SImode ? 0x2810 :
- (tomode == SFmode ? 0x1010 :
- 0x0810)));
- cname = (tomode == HImode ? "FX2I" :
- (tomode == SImode ? "FX2L" :
- (tomode == SFmode ? "FX2S" :
- "FX2D")));
- coperands[1] = (frommode == XFmode ? operands[1] : tmprtx);
- coperands[0] = deepen (operands[0]);
- output_sane_op (coperands, 2, cop, cname);
- }
- /* Pop the result if it wasn't memory-resident */
- if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
- {
- output_sane_pop (opnds[0]);
- }
- /* Finish cleaning up the stack. */
- if (spacetmp + space1 > 0)
- {
- sprintf (tmpbuf, "add%.w #%d,sp", spacetmp + space1);
- output_asm_insn(tmpbuf, NULL);
- }
- return "";
- }
-
- /* Output a 3(2)-address operation that uses SANE. This routine will do
- everything including type conversions, since this helps it use the
- stack somewhat more efficiently. */
-
- char *
- output_sane_3 (opnds, op, name)
- rtx *opnds;
- int op;
- char *name;
- {
- char tmpbuf[100], *cname;
- enum machine_mode mode0 = GET_MODE (opnds[0]);
- enum machine_mode mode2 = GET_MODE (opnds[2]);
- int space0 = 0, space2 = 0, spacetmp = 0, space;
- int cop;
- rtx operands[3], moperands[3], coperands[2], tmprtx, tmpop;
-
- if (mode0 != XFmode)
- spacetmp = GET_MODE_SIZE (XFmode);
- if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
- space0 = GET_MODE_SIZE (GET_MODE (opnds[0]));
- if (REG_P (opnds[2]) || GET_CODE (opnds[2]) == CONST_DOUBLE)
- space2 = GET_MODE_SIZE (GET_MODE (opnds[2]));
- space = spacetmp + space2 + space0;
- /* Reserve needed space for all our tmps and operands. */
- if (spacetmp > 0)
- {
- sprintf(tmpbuf, "sub%.w #%d,sp", spacetmp);
- output_asm_insn(tmpbuf, NULL);
- tmprtx = STKOFF (XFmode, space0 + space2);
- }
- if (space2 > 0)
- {
- output_sane_push(opnds[2]);
- operands[2] = STKOFF (GET_MODE (opnds[2]), space0);
- }
- else
- {
- operands[2] = opnds[2];
- }
- if (space0 > 0)
- {
- output_sane_push(opnds[0]);
- operands[0] = STKOFF (GET_MODE (opnds[0]), 0);
- }
- else
- {
- operands[0] = opnds[0];
- }
- /* Now everything is a pointer to memlocs where the numbers reside. */
- /* First order of business is to make sure the input-output operand
- is of extended type. If not, then we convert into a reserved place
- and if so, we maybe put it on the stack anyway. */
- if (mode0 != XFmode)
- {
- cop = (mode0 == HImode ? 0x200e :
- (mode0 == SImode ? 0x280e :
- (mode0 == SFmode ? 0x100e :
- 0x080e)));
- cname = (mode0 == HImode ? "FI2X" :
- (mode0 == SImode ? "FL2X" :
- (mode0 == SFmode ? "FS2X" :
- "FD2X")));
- coperands[1] = operands[0];
- coperands[0] = deepen (tmprtx);
- output_sane_op (coperands, 2, cop, cname);
- moperands[0] = tmprtx;
- }
- else
- {
- moperands[0] = operands[0];
- }
- tmpop = moperands[0];
- moperands[0] = deepen (moperands[0]);
- moperands[1] = operands[2];
- /* Now we're all set to do the operation proper. */
- output_sane_op (moperands, 2, op, name);
- /* The result of the operation is still extended, so we may need to
- do another conversion. Fortunately, the extended result is already in
- memory, so we don't need to allocate, but the final result may need
- to be sent back to regs. */
- if (mode0 != XFmode)
- {
- cop = (mode0 == HImode ? 0x2010 :
- (mode0 == SImode ? 0x2810 :
- (mode0 == SFmode ? 0x1010 :
- 0x0810)));
- cname = (mode0 == HImode ? "FX2I" :
- (mode0 == SImode ? "FX2L" :
- (mode0 == SFmode ? "FX2S" :
- "FX2D")));
- coperands[0] = deepen (operands[0]);
- coperands[1] = tmpop;
- output_sane_op (coperands, 2, cop, cname);
- }
- /* SANE calls all done, now clean up. */
- /* Pop the result if it had to be pushed originally. */
- if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
- {
- output_sane_pop (opnds[0]);
- }
- /* Deallocate everything else. */
- if (spacetmp + space2 > 0)
- {
- sprintf (tmpbuf, "add%.w #%d,sp", spacetmp + space2);
- output_asm_insn(tmpbuf, NULL);
- }
- /* All the code has already been dumped out. */
- return "";
- }
-
- /* Push a SANE number onto the stack (usually from a reg). */
-
- output_sane_push (x)
- rtx x;
- {
- rtx pusherands[2];
-
- pusherands[0] = gen_rtx (MEM, GET_MODE (x),
- gen_rtx (PRE_DEC, Pmode, stack_pointer_rtx));
- pusherands[1] = x;
- switch (GET_MODE (x))
- {
- case HImode:
- output_asm_insn ("move%.w %1,%0", pusherands);
- break;
- case SImode:
- case SFmode:
- output_asm_insn ("move%.l %f1,%0", pusherands);
- break;
- case DFmode:
- output_move_double (pusherands);
- break;
- case XFmode:
- output_move_extended (pusherands);
- break;
- default:
- abort();
- }
- }
-
- /* Pop a SANE number off the stack into a given place (most likely a reg). */
-
- output_sane_pop (x)
- rtx x;
- {
- rtx poperands[2];
-
- poperands[0] = x;
- poperands[1] = gen_rtx (MEM, GET_MODE (x),
- gen_rtx (POST_INC, Pmode, stack_pointer_rtx));
- switch (GET_MODE (x))
- {
- case HImode:
- output_asm_insn ("move%.w %1,%0", poperands);
- break;
- case SImode:
- case SFmode:
- output_asm_insn ("move%.l %1,%0", poperands);
- break;
- case DFmode:
- output_move_double (poperands);
- break;
- case XFmode:
- output_move_extended (poperands);
- break;
- default:
- abort();
- }
- }
-
- /* Issue the basic SANE calling sequence; push addresses of operands (which
- must already be in memory), push the op code, then trap. The trap
- will pop everything itself, so no cleanup needed. */
-
- output_sane_op (moperands, numopnds, op, name)
- rtx *moperands;
- int numopnds, op;
- char *name;
- {
- char tmpbuf[100];
-
- if (numopnds > 1)
- output_asm_insn ("pea %1", moperands);
- if (numopnds > 0)
- output_asm_insn ("pea %0", moperands);
- sprintf (tmpbuf, TARGET_GAS?"movew #$%x,sp@- ; %s":"move.w #$%x,-(sp) ; %s", op, name);
- output_asm_insn (tmpbuf, NULL);
- output_asm_insn (TARGET_GAS?".word $a9eb ; FP68K":"dc.w $a9eb ; FP68K", NULL);
- }
-
- /* Return a REG that occurs in ADDR with coefficient 1.
- ADDR can be effectively incremented by incrementing REG. */
-
- static rtx
- find_addr_reg (addr)
- rtx addr;
- {
- while (GET_CODE (addr) == PLUS)
- {
- if (GET_CODE (XEXP (addr, 0)) == REG)
- addr = XEXP (addr, 0);
- else if (GET_CODE (XEXP (addr, 1)) == REG)
- addr = XEXP (addr, 1);
- else if (CONSTANT_P (XEXP (addr, 0)))
- addr = XEXP (addr, 1);
- else if (CONSTANT_P (XEXP (addr, 1)))
- addr = XEXP (addr, 0);
- else
- abort ();
- }
- if (GET_CODE (addr) == REG)
- return addr;
- abort ();
- }
-
- char *
- output_move_const_long_double (operands)
- rtx *operands;
- {
- {
- int code = standard_68881_constant_p (operands[1]);
-
- if (code != 0)
- {
- static char buf[40];
-
- sprintf (buf, "fmovecr #$%x,%%0", code & 0xff);
- return buf;
- }
- return "fmove.x %1,%0";
- }
- }
-
- char *
- output_move_const_double (operands)
- rtx *operands;
- {
- {
- int code = standard_68881_constant_p (operands[1]);
-
- if (code != 0)
- {
- static char buf[40];
-
- sprintf (buf, "fmovecr #$%x,%%0", code & 0xff);
- return buf;
- }
- return "fmove.d %1,%0";
- }
- }
-
- char *
- output_move_const_single (operands)
- rtx *operands;
- {
- {
- int code = standard_68881_constant_p (operands[1]);
-
- if (code != 0)
- {
- static char buf[40];
-
- sprintf (buf, "fmovecr #$%x,%%0", code & 0xff);
- return buf;
- }
- return "fmove.s %1,%0";
- }
- }
-
- /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
- from the "fmovecr" instruction.
- The value, anded with 0xff, gives the code to use in fmovecr
- to get the desired constant. */
-
- /* This seems dubious for MPW... */
-
- int
- standard_68881_constant_p (x)
- rtx x;
- {
- union {double d; int i[2];} u;
- register double d;
- u.i[0] = CONST_DOUBLE_LOW (x);
- u.i[1] = CONST_DOUBLE_HIGH (x);
- d = u.d;
-
- if (d == 0)
- return 0x0f;
- /* Note: there are various other constants available
- but it is a nuisance to put in their values here. */
- if (d == 1)
- return 0x32;
- if (d == 10)
- return 0x33;
- if (d == 100)
- return 0x34;
- if (d == 10000)
- return 0x35;
- if (d == 1e8)
- return 0x36;
- if (GET_MODE (x) == SFmode)
- return 0;
- if (d == 1e16)
- return 0x37;
- /* larger powers of ten in the constants ram are not used
- because they are not equal to a `double' C constant. */
- return 0;
- }
-
- /* Print out a string in MPW Asm-approved syntax. Main trickiness is
- to recognize non-printing characters and put them out as raw bytes,
- while keeping as many printable characters in a string as possible
- (saves space in asm code and makes it more readable too). */
-
- /* newline/cr character mapping was handled at lex time... */
-
- output_mpw_string(fp, str, size)
- FILE *fp;
- char *str;
- int size;
- {
- unsigned char ch;
- int i,empty = 1;
-
- for (i = 0; i < size; ++i)
- {
- ch = str[i];
- if ((ch < ' ') || (ch > '~') || (ch == '"') || (ch == '\''))
- {
- if (!empty) fprintf(fp, TARGET_GAS?"\"\n":"'\n");
- ASM_OUTPUT_BYTE(fp,ch);
- empty = 1;
- }
- else
- {
- if (empty) fprintf(fp, TARGET_GAS?"\t.ascii \"":"\tDC.B '");
- fprintf(fp, "%c", ch);
- empty = (i > 0 && i % 60 == 0);
- if (empty) fprintf(fp, TARGET_GAS?"\"\n":"'\n");
- }
- }
- if (!empty) fprintf(fp, TARGET_GAS?"\"\n":"'\n");
- /* Ending NUL char is part of the string's "size", so doesn't need to be added. */
- }
-
- /* Print out a floating rtx in some useful way. */
-
- #include "real.h"
-
- output_mpw_float (fp, x)
- FILE *fp;
- rtx x;
- {
- union { REAL_VALUE_TYPE f; int i[3]; } u;
- double d;
- float f;
-
- u.i[0] = CONST_DOUBLE_LOW (x);
- u.i[1] = CONST_DOUBLE_HIGH (x);
- u.i[2] = CONST_DOUBLE_TOP (x);
-
- switch (GET_MODE (x))
- {
- case SFmode:
- f = u.f;
- fprintf (fp, "\"%.9g\"", f);
- break;
- case DFmode:
- d = u.f;
- fprintf (fp, "\"%.20g\"", d);
- break;
- case XFmode:
- fprintf (fp, "\"%.30g\"", u.f);
- break;
- default:
- abort ();
- }
- }
-
- output_mpw_float_as_int (fp, x)
- FILE *fp;
- rtx x;
- {
- union { REAL_VALUE_TYPE f; int i[3]; } u;
- union { float f; int i[1]; } u2;
-
- u.i[0] = CONST_DOUBLE_LOW (x);
- u.i[1] = CONST_DOUBLE_HIGH (x);
- u.i[2] = CONST_DOUBLE_TOP (x);
-
- u2.f = u.f;
-
- switch (GET_MODE (x))
- {
- case SFmode:
- fprintf (fp, "%d", u2.i[0]);
- break;
- case DFmode:
- case XFmode:
- fprintf (stderr, "Can't integerize a double or extended const!\n");
- default:
- abort ();
- }
- }
-
- /* Printing extended floats is a little tricky, since both the compiler and
- the target machines care about the 10/12-byte size. */
-
- output_mpw_long_double (fp, x)
- FILE *fp;
- REAL_VALUE_TYPE x;
- {
- union { REAL_VALUE_TYPE f; short s[6]; } u;
- int a = 0;
-
- u.f = x;
-
- fprintf (fp, TARGET_GAS?"\t.word %d,":"\tDC.W %d,", u.s[0]);
- if (TARGET_68881)
- {
- #ifdef mc68881
- fprintf (fp, "%d,", u.s[1]);
- a = 1;
- #else
- fprintf (fp, "0,");
- a = 0;
- #endif
- }
- fprintf (fp, "%d,%d,%d,%d ; %.30g\n",
- u.s[a+1], u.s[a+2], u.s[a+3], u.s[a+4], x);
- }
-
- /* We need to recognize all possible references to global data. */
-
- global_data_ref_p (addr)
- rtx addr;
- {
- switch (GET_CODE (addr))
- {
- case SYMBOL_REF:
- {
- char *name = XSTR (addr, 0);
-
- return (name[0] == '2');
- }
- case PLUS:
- return (global_data_ref_p (XEXP (addr, 0))
- || global_data_ref_p (XEXP (addr, 1)));
- case CONST:
- return global_data_ref_p (XEXP (addr, 0));
- default:
- return 0;
- }
- return 0;
- }
-
- /* Test a string to see if it matches any register names. A few extra
- tests on individual chars to optimize - a more serious approach would
- involve a binary search tree or something. Don't bother unless this
- can be proved to take significant time! */
-
- /* Names not in the regular reg_names list that the assembler knows about
- and will choke on if you attempt to use them as labels. */
-
- char *obscure_reg_names[] = {
- "sp",
- "a7",
- "za7",
- "pc",
- "zpc",
- "ccr",
- "sr",
- "usp",
- "sfc",
- "dfc",
- "cacr",
- "vbr",
- "caar",
- "msp",
- "isp",
- NULL };
-
- mpw_register_name (str)
- char *str;
- {
- int i;
- extern char* reg_names[];
-
- if (str[0] == 'd' || str[0] == 'a' || str[0] == 'f')
- {
- for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
- if (strcmp (str, reg_names[i]) == 0)
- return 1;
- }
- if (str[0] == 'z' && (str[1] == 'd' || str[1] == 'a'))
- {
- for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
- if (strcmp (str, reg_names[i]+1) == 0)
- return 1;
- }
- /* There are other more obscure register names to test as well. */
- for (i = 0; obscure_reg_names[i]; ++i)
- if (strcmp (str, obscure_reg_names[i]) == 0)
- return 1;
- return 0;
- }
-
- char *
- avoid_mpw_register_name (name)
- char *name;
- {
- int typechar = ('0' <= name[0] && name[0] <= '9');
- char *newname = name;
-
- if (mpw_register_name (name + typechar))
- {
- /* should warn that name is being changed. */
- newname = (char *) xmalloc (strlen (name) + 2);
- strcpy (newname, name);
- strcat (newname, "_");
- warning ("`%s' is a register name; changing to `%s'",
- name + typechar, newname + typechar);
- }
- return newname;
- }
-
- /* Implementing -b requires saving up strings somewhere. */
-
- char *lbls[100];
- char *strs[100];
- int lsix = 0;
- int totlen = 0;
-
- record_a_string(lbl, str)
- char *lbl, *str;
- {
- if (lsix >= 99) abort ();
- lbls[lsix] = lbl;
- strs[lsix] = str;
- totlen += strlen(str) + 1;
- totlen += (totlen & 1); /* keeps it aligned */
- lsix++;
- }
-
- /* Functions compiled with -b have all their strings at the end of the
- function, preceded by a length field. */
-
- /* Should scan a linked list of strings saved up for this function,
- not a fixed-size array. */
-
- dump_local_strings (fp)
- FILE *fp;
- {
- int i;
-
- /* Only really need the length word for debugging, otherwise skip it. */
- if (TARGET_MACSBUG)
- fprintf (fp, TARGET_GAS?"\t.word %d\n":"\tDC.W %d\n", totlen);
- for (i = 0; i < lsix; ++i)
- {
- /* String might be referred to from elsewhere within this file. */
- fprintf (fp, "\tENTRY ");
- assemble_name (fp, lbls[i]);
- fprintf (fp, "\n");
- assemble_name (fp, lbls[i]);
- output_mpw_string (fp, strs[i], strlen(strs[i])+1);
- fprintf (fp, "\tALIGN\n");
- }
- lsix = totlen = 0;
- }
-
- int init_out_mac()
- {
- #define INIT_OUT_MAC
- #include "init.c"
- }